package model

import (
	"time"

	"bmember/pkg/util"
)

const (
	// MsgStatusWaiting 等待发送/消费
	MsgStatusWaiting int8 = 1
	// MsgStatusFinished 发送/消费成功
	MsgStatusFinished int8 = 2
	// MsgStatusAborted 废弃
	MsgStatusAborted int8 = 3

	MsgTypeForSending   int8 = 1
	MsgTypeForConsuming int8 = 2
)

// Message 消息
type Message struct {
	// id
	Id int64 `json:"id" sql:"id"`
	// 消息 topic
	Topic string `json:"topic" sql:"topic"`
	// 消息内容
	Content []byte `json:"content" sql:"content"`
	// 状态
	Status int8 `json:"status" sql:"status"`
	// 预期发送时间
	Eta time.Time `json:"eta" sql:"eta"`
	// 重试次数
	RetryCount int8 `json:"retry_count" sql:"retry_count"`
	// 消息类型
	MsgType int8 `json:"msg_type" sql:"msg_type"`
	// 创建时间
	CreatedAt time.Time `json:"created_at" sql:"created_at"`
	// 更新时间
	UpdatedAt time.Time `json:"updated_at" sql:"updated_at"`
}

func NewMessage(topic string, content interface{}, msgType int8) *Message {
	var conB []byte
	switch content.(type) {
	case []byte:
		conB = content.([]byte)
	default:
		conB, _ = json.Marshal(content)
	}
	now := util.GetNow()
	return &Message{
		Topic:     topic,
		Content:   conB,
		Status:    MsgStatusWaiting,
		MsgType:   msgType,
		CreatedAt: now,
		UpdatedAt: now,
		Eta:       now,
	}
}

// SetEta 设置使用发送时间
func (m *Message) SetEta(eta time.Time) {
	if !util.IsZeroTime(eta) {
		m.Eta = eta
		m.UpdatedAt = util.GetNow()
	}
}

// ForSending 用于发送的消息
func (m *Message) ForSending() {
	m.MsgType = MsgTypeForSending
}

// IsForSending 用于发送的消息
func (m *Message) IsForSending() bool {
	return m.MsgType == MsgTypeForSending
}

// ForConsuming 用于消费的消息
func (m *Message) ForConsuming() {
	m.MsgType = MsgTypeForConsuming
}

// IsForConsuming 用于消费的消息的
func (m *Message) IsForConsuming() bool {
	return m.MsgType == MsgTypeForConsuming
}

// Success 成功
func (m *Message) Success() {
	m.Status = MsgStatusFinished
	m.RetryCount += 1
	m.UpdatedAt = util.GetNow()
}

// Abort 废弃
func (m *Message) Abort() {
	m.Status = MsgStatusAborted
	m.UpdatedAt = util.GetNow()
}

// IsFinished 是否已经结束
func (m *Message) IsFinished() bool {
	return m.Status == MsgStatusFinished || m.Status == MsgStatusAborted
}

// NeedRetry 需要重试
func (m *Message) NeedRetry() {
	m.Status = MsgStatusWaiting
	m.RetryCount += 1
	now := util.GetNow()
	switch m.RetryCount {
	case 0:
		m.Eta = now.Add(1 * time.Second)
	case 1:
		m.Eta = now.Add(5 * time.Second)
	case 2:
		m.Eta = now.Add(15 * time.Second)
	case 3:
		m.Eta = now.Add(2 * time.Minute)
	case 5:
		m.Eta = now.Add(5 * time.Minute)
	default:
		m.Eta = now.Add(30 * time.Minute)
	}
	m.UpdatedAt = now
}
